home *** CD-ROM | disk | FTP | other *** search
Text File | 2001-01-26 | 53.6 KB | 1,653 lines |
- ## -*-Tcl-*- (nowrap)
- # ==========================================================================
- # Statistical Modes - an extension package for Alpha
- #
- # FILE: "sasMode.tcl"
- # created: 01/15/00 {07:15:32 pm}
- # last update: 01/26/01 {12:22:11 pm}
- # Description:
- #
- # For SAS syntax files. SAS is not my statistical package of choice.
- # Anyone who has access to a newer manual should feel free to update the
- # list of keywords and send them along to me.
- #
- # Author: Craig Barton Upright
- # E-mail: <cupright@princeton.edu>
- # mail: Princeton University, Department of Sociology
- # Princeton, New Jersey 08544
- # www: <http://www.princeton.edu/~cupright>
- #
- # -------------------------------------------------------------------
- #
- # Copyright (c) 2000-2001 Craig Barton Upright
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- #
- # ==========================================================================
- ##
-
- # ===========================================================================
- #
- # ◊◊◊◊ Initialization of SAS mode ◊◊◊◊ #
- #
-
- alpha::mode SAS 2.1.1 sasMenu {*.sas} {
- sasMenu electricReturn electricTab electricSemicolon electricBraces
- } {
- # We require 7.4b21 for prefs handling.
- alpha::package require -loose AlphaTcl 7.4b21
- addMenu sasMenu "SAS" SAS
- set unixMode(sas) {SAS}
- set modeCreator(SaS6) {SAS}
- } uninstall {
- this-file
- } help {
- file "Statistical Modes Help"
- } maintainer {
- "Craig Barton Upright" <cupright@princeton.edu>
- <http://www.princeton.edu/~cupright/>
- }
-
- hook::register quitHook SAS::quitHook
-
- proc sasMenu {} {}
-
- proc sasMode.tcl {} {}
-
- namespace eval SAS {}
-
- # ===========================================================================
- #
- # ◊◊◊◊ Setting SAS mode variables ◊◊◊◊ #
- #
-
- # Removing obsolete preferences from earlier versions.
-
- set oldvars {
- addOptions addParameters addProcs addSubProcs autoMark don'tRemindMe
- electricTab funcExpr functionColor indentSlashEndLines keywordColor
- parseExpr procColor subprocColor sasHelp
- }
-
- foreach oldvar $oldvars {prefs::removeObsolete SASmodeVars($oldvar)}
-
- unset oldvar oldvars
-
- # ===========================================================================
- #
- # Standard preferences recognized by various Alpha procs
- #
-
-
- newPref var fillColumn {75} SAS
- newPref var leftFillColumn {0} SAS
- newPref var prefixString {* } SAS
- newPref var wordBreak {[a-zA-Z0-9]+} SAS
- newPref var wordBreakPreface {[^-a-zA-Z0-9]} SAS
- newPref flag wordWrap {0} SAS
-
- # ===========================================================================
- #
- # Flag preferences
- #
-
- newPref flag autoMark {0} SAS {SAS::rebuildMenu markSasFileAs}
-
- # Indent all continued commands, indicated by the lack of a semi-colon at
- # the end of a line, by the full indentation amount rather than half.
- newPref flag fullIndent {1} SAS {SAS::rebuildMenu markSasFileAs}
-
- # By default command double-click will send a command to on-line help, and
- # option double-click sends a command to the local SAS application.
- # Check this box to switch these key combinations.
- newPref flag localHelp {0} SAS {SAS::rebuildMenu sasHelp}
-
- # Check this box if your keyboard does not have a "Help" key. This will
- # change some of the menu's key bindings.
- newPref flag noHelpKey {0} SAS {SAS::rebuildMenu sasHelp}
-
- # Set the list of flag preferences which can be changed in the menu.
-
- set SASPrefsInMenu [list \
- "localHelp" \
- "noHelpKey" \
- "fullIndent" \
- ]
-
- # ===========================================================================
- #
- # Variable preferences
- #
-
- # Enter additional arguments to be colorized.
- newPref var addArguments {} SAS {SAS::colorizeSAS}
-
- # Enter additional SAS proc commands to be colorized.
- newPref var addCommands {} SAS {SAS::colorizeSAS}
-
- # Command double-clicking on a SAS keyword will send it to this url for a
- # help reference page.
- newPref url helpUrl {} SAS
-
- # The "SAS Home Page" menu item will send this url to your browser.
- newPref url sasHomePage {http://www.sas.com/} SAS
-
- # Click on "Set" to find the local SAS application.
- newPref sig sasSig {SaS6} SAS
-
- # ===========================================================================
- #
- # Color preferences
- #
- # Nomenclature notes:
- #
- # SAS seems to have five levels of possible keywords.
- #
- # 1. the top level "proc" specification: anova, freq varcomp
- # 2. sub-level procs (or "subprocs"): rename, value, range
- # 2. "arguments", which require no parameters: ls, missover, in1
- # 3. "options", which require parameters: converge, data, gamma
- # 4. "parameters", preset as opposed to user supplied: full, part
- #
- # The default setup of this mode is to colorize all of procs and subprocs
- # blue; arguments, options, and parameters are magenta. The user does not
- # have to specify all of these different levels -- only Argument, Command,
- # Comment, String, and Symbol colors appear in the preferences.
- #
- # Of these four statistical packages, I am the most unfamiliar with SAS.
- # This mode is my good-hearted attempt, but is distributed with no
- # assurances that it is complete.
- #
-
- # See the Statistical Modes Help file for an explanation of these different
- # categories, and lists of keywords.
- newPref color argumentColor {magenta} SAS {SAS::colorizeSAS}
- newPref color commandColor {blue} SAS {SAS::colorizeSAS}
- newPref color commentColor {red} SAS {stringColorProc}
- newPref color stringColor {green} SAS {stringColorProc}
-
- # The color of symbols such as "/", "@", etc.
- newPref color symbolColor {magenta} SAS {SAS::colorizeSAS}
-
- regModeKeywords -e {*} -b {/*} {*/} \
- -c $SASmodeVars(commentColor) \
- -s $SASmodeVars(stringColor) SAS {}
-
- # ===========================================================================
- #
- # Flag Flip
- #
- # Called by menu items, change the value of flag preferences.
- #
-
- proc SAS::flagFlip {pref} {
-
- global mode SASmodeVars
-
- set SASmodeVars($pref) [expr {$SASmodeVars($pref) ? 0 : 1}]
- set oldMode $mode
- set mode "SAS"
- synchroniseModeVar $pref $SASmodeVars($pref)
- set mode $oldMode
- if {$SASmodeVars($pref)} {
- set end "on"
- } else {
- set end "off"
- }
- message "The \"$pref\" preference is now $end."
- }
-
- # ===========================================================================
- #
- # Comment Character variables for Comment Line / Paragraph / Box menu items.
- #
-
- set SAS::commentCharacters(General) "* "
- set SAS::commentCharacters(Paragraph) [list "/* " " */" " * "]
- set SAS::commentCharacters(Box) [list "/*" 2 "*/" 2 "*" 3]
-
- # The Comment Line command is hard-wired -- except for the C and C++ modes,
- # if the commentCharacters(Paragraph) are different, then Comment Line will
- # automatically be bracketed. Thus I am simply redefining the command-d
- # key-binding to ignore commentLine
-
- Bind 'd' <c> {insertPrefix} SAS
-
- # ===========================================================================
- #
- # ◊◊◊◊ Keyword Dictionaries ◊◊◊◊ #
- #
-
- # Making sure that SASUserCommands and SASUserArguments exist.
- # These will be over-ridden if they are loaded from a ${mode}Prefs.tcl file.
- #
-
- set SASUserCommands ""
- set SASUserArguments ""
-
- # ===========================================================================
- #
- # ◊◊◊◊ SAS Commands ◊◊◊◊ #
- #
-
- set SASCommands {
- aceclus anova calis cancorr candisc catmod cluster corresp discrim
- factor fastclus format freq genmod glm glmmod inbreed kde krige2d
- lattice lifereg lifetest loess logistic mds mixed modeclus multtest
- nested nlin nlmixed npar1way orthoreg phreg plan pls princomp prinqual
- probit proc reg rsreg score stepdisc surveymeans surveyreg surveyselect
- tpspline transreg tree ttest varclus varcomp variogram
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ SAS Subprocs ◊◊◊◊ #
- #
-
- set SASSubprocs {
- arima array autoreg average axis1 axis2 by cards centroid choro "class"
- col colblock colcopy collist colpct cols column columns complete
- computab contents control data datasource density dftest do end
- endogenous estimate exogenous filename fit footnote1 footnote2
- footnote3 footnote4 forecast form gmap goptions gplot id identify
- infile input instruments keep label lagged last legend legend1 legend2
- length let libname macro merge model monthly options output parms
- pattern1 pattern2 pattern3 pattern4 pattern5 pattern6 pattern7 pattern8
- plot print put quarterly quit range rename restrict retain return row
- rowblock rowcopy rowlist rows run select set solve sort sumby symbol
- symbol1 symbol2 symbol3 symbol3 symbol4 tables threshold title title1
- title2 title3 title4 value var weights where
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ SAS Arguments ◊◊◊◊ #
- #
-
- set SASArguments {
- _col_ _row_ all b bcorr bcov bsscp bvreg c cback clogit clogits colors
- corr corrb dbname device distance eof f garch gr2 h haxis hpos href i
- in1 int intercept interval j joint l lead logit logits lrecl ls lsd
- lspace map marginal marginals maxit maxiter mean means method
- "missover" mpsprt mySAS nodesign nogls noint noiter noparm noprint
- noprofile noresponse notrans noun obs oneway outall outby outcont
- outest pcorr pcov pp printout proby psscp qq red redundancy regwf regwq
- response s scjeffe seb short short shortanova sidak simple smc smm snk
- spcorr sqpcorr sqspcorr stb stdmean survey t tcorr tcov trend tsscp
- tukey type v vdep vpos w waller wcorr wcov wdep wsscp wteg
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ SAS Options ◊◊◊◊ #
- #
-
- set SASOptions {
- absolute absorb archtest border converge crosscorr diagonal dif dwprob
- filetype frame from identity initial intnx log manova maxiter metric
- mulripass nlag nlags noconstant noobs noprint ourstat out outfull
- outselect outstat overlay partial prefix rannor sing singular to weight
- xlog
- }
-
-
- # ===========================================================================
- #
- # ◊◊◊◊ SAS Parameters ◊◊◊◊ #
- #
-
- set SASParameters {
- absolute absorb and asmc average biweight centroid circle complete
- converge density diagonal else eml epanechnikov equamax flexible
- formatted full identity if if in initial internal join kj manova max
- maxiter mcquitty median metric multipass needle no none normal npar one
- orthmox ourstat out outstat p percent plus prefix procustes promax
- proportion qtrvars quarimax random sing single singular smc sorted
- special spline splines star test then triweight twostage uniform
- varimax ward weight yes
- }
-
- # ===========================================================================
- #
- # Colorize SAS.
- #
- # Set all keyword lists, and colorize.
- #
- # Could also be called in a <mode>Prefs.tcl file
- #
-
- proc SAS::colorizeSAS {{pref ""}} {
-
- global SASmodeVars SASCommands SASSubprocs SASArguments
- global SASOptions SASParameters SASUserCommands SASUserArguments
-
- global SASlowerCaseCmds SASbothCaseCommands SASArgumentsList SAScmds
-
- # Procs and Subprocs only, for SAS::Completion::Command.
- set SASlowerCaseCommands [concat \
- $SASCommands $SASSubprocs $SASmodeVars(addCommands) $SASUserCommands]
- message "Creating ALL CAP commands for SAS mode …"
- set SASupperCaseCommands [string toupper $SASlowerCaseCommands]
-
- set SASbothCaseCommands [lsort [concat \
- $SASlowerCaseCommands $SASupperCaseCommands]]
- # Arguments, Options, Parameters
- set SASArgumentsList [concat \
- $SASArguments $SASmodeVars(addArguments) $SASOptions \
- $SASParameters $SASUserArguments]
-
- # Then, create the list of all keywords for completions. SAS
- # keywords are not case-sensitive. To allow for different user
- # styles, we'll include lower case commands as well as ALL CAPS.
- set SASlowerCaseCmds [concat \
- $SASlowerCaseCommands $SASArgumentsList]
-
- set SASupperCaseCmds [string toupper $SASlowerCaseCmds]
-
- set SAScmds [lsort [lunique [concat \
- $SASlowerCaseCmds $SASupperCaseCmds]]]
- message ""
-
- # Commands
- regModeKeywords -a \
- -k $SASmodeVars(commandColor) SAS $SASbothCaseCommands
-
- # Arguments, Options, Parameters
- regModeKeywords -a \
- -k $SASmodeVars(argumentColor) SAS $SASArgumentsList
-
- # Symbols
- regModeKeywords -a \
- -k $SASmodeVars(symbolColor) SAS {|} \
- -i "+" -i "-" -i "_" -i "\\" \
- -I $SASmodeVars(symbolColor)
-
- if {$pref != ""} {refresh}
- }
-
- # Call this now.
-
- SAS::colorizeSAS
-
- # ===========================================================================
- #
- # Reload Completions.
- #
- #
- # This is now an obsolete proc.
- #
-
- proc SAS::reloadCompletions {} {
- alertnote "\"SAS::reloadCompletions\" is an obsolete proc.\
- It should be removed from your SASPrefs.tcl file."
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Key Bindings, Electrics ◊◊◊◊ #
- #
- # abbreviations: <o> = option, <z> = control, <s> = shift, <c> = command
- #
-
- # Known bug: Key-bindings from other global menus might conflict with those
- # defined in the SAS menu. This will help ensure that this doesn't happen.
-
- Bind 's' <cs> {SAS::switchToSas} SAS
- Bind 'p' <cs> {SAS::processFile} SAS
- Bind 'p' <csz> {SAS::processSelection} SAS
- Bind 'p' <cs> {SAS::insertPath} SAS
-
- Bind 'n' <sz> {SAS::nextCommand} SAS
- Bind 'p' <sz> {SAS::prevCommand} SAS
- Bind 's' <sz> {SAS::selectCommand} SAS
- Bind 'c' <sz> {SAS::copyCommand} SAS
-
- Bind 'i' <cz> {SAS::reformatCommand} SAS
-
- Bind '\)' {SAS::electricRight "\)"} SAS
-
- # For those that would rather use arrow keys to navigate. Up and down
- # arrow keys will advance to next/prev command, right and left will also
- # set the cursor to the top of the window.
-
- Bind up <sz> {SAS::prevCommand 0 0} SAS
- Bind left <sz> {SAS::prevCommand 0 1} SAS
- Bind down <sz> {SAS::nextCommand 0 0} SAS
- Bind right <sz> {SAS::nextCommand 0 1} SAS
-
- # ===========================================================================
- #
- # SAS Electric Semi
- #
- # Inserts a semi, carriage return, and indents properly.
- #
-
- proc SAS::electricSemi {} {
-
- if {[literalChar]} {
- typeText {;}
- } else {
- typeText {;}
- bind::CarriageReturn
- }
- }
-
- # ===========================================================================
- #
- # SAS Carriage Return
- #
- # Inserts a carriage return, and indents properly.
- #
-
- proc SAS::carriageReturn {} {
-
- global SASmodeVars
-
- if {[isSelection]} {
- deleteSelection
- }
- set pos1 [lineStart [getPos]]
- set pos2 [getPos]
- if {[regexp {^([\t ])*(\}|\))} [getText $pos1 $pos2]]} {
- createTMark temp $pos2
- catch {bind::IndentLine}
- gotoTMark temp ; removeTMark temp
- }
- insertText "\r"
- catch {bind::IndentLine}
- }
-
- # ===========================================================================
- #
- # SAS Electric Left, Right
- #
- # Adapted from "tclMode.tcl"
- #
-
- proc SAS::electricLeft {} {
-
- if {[literalChar]} {
- typeText "\{"
- return
- }
- set pat "\}\[ \t\r\n\]*(else(if)?)\[ \t\r\n\]*\$"
- set pos [getPos]
- if { [set result [findPatJustBefore "\}" $pat $pos word]] == "" } {
- insertText "\{"
- return
- }
- # we have an if/else(if)/else
- switch -- $word {
- "else" {
- deleteText [lindex $result 0] $pos
- elec::Insertion "\} $word \{\r\t••\r\}\r••"
- }
- "elseif" {
- deleteText [lindex $result 0] $pos
- elec::Insertion "\} $word \{••\} \{\r\t••\r\}\r••"
- }
- }
- }
-
- proc SAS::electricRight {{char "\}"}} {
-
- if {[literalChar]} {
- typeText $char
- return
- }
- set pos [getPos]
- typeText $char
- if {![regexp {[^ \t]} [getText [lineStart $pos] $pos]]} {
- set pos [lineStart $pos]
- createTMark temp [getPos]
- catch {bind::IndentLine}
- gotoTMark temp ; removeTMark temp
- bind::CarriageReturn
- }
- if {[catch {blink [matchIt $char [pos::math $pos - 1]]}]} {
- beep ; message "No matching $char !!"
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Indentation ◊◊◊◊ #
- #
- # SAS::correctIndentation is necessary for Smart Paste, and returns the
- # correct level of indentation for the current line. SAS::indentLine uses
- # this level to indent the current line.
- #
- # We have two level of indentation in SAS, for the continuation of
- # commands, in which case we simply indent to the amount of the SAS mode
- # variable indentationAmount, and for nexted braces.
- #
- # In SAS::correctIndentation, we grab the previous non-commented line,
- # remove all of the characters besides braces and quotes, and then convert
- # it all to a list to be evaluated. Braces contained within quotes, as
- # well as literal characters, should all be ignored and the remaining
- # braces are used to determine the correct level of nesting.
- #
-
- proc SAS::indentLine {{pos ""}} {
-
- if {$pos == ""} {set pos [getPos]}
- # Get details of current line.
- set posBeg [lineStart [getPos]]
- set text [getText $posBeg [nextLineStart $posBeg]]
- regexp {^[ \t]*} $text white
- set posNext1 [pos::math $posBeg + [string length $white]]
- set posNext2 [pos::math $posNext1 + 1]
- if {[pos::compare $posNext2 > [maxPos]]} {
- set posNext2 [maxPos]
- }
- # Determine the correct level of indentation for this line, given the
- # next character.
- set lwhite [SAS::correctIndentation $pos [getText $posNext1 $posNext2]]
- set lwhite [text::indentOf $lwhite]
- if {$white != $lwhite} {
- replaceText $posBeg $posNext1 $lwhite
- }
- goto [pos::math $posBeg + [string length $lwhite]]
- }
-
- proc SAS::correctIndentation {pos {next ""}} {
-
- global mode indent_amounts SASmodeVars
-
- if {$mode == "SAS"} {
- set continueIndent [expr {$SASmodeVars(fullIndent) + 1}]
- } else {
- set continueIndent 2
- }
-
- set posBeg [lineStart $pos]
- # Get information about this line, previous line ...
- set thisLine [SAS::getCommandLine $posBeg 1 1]
- set prevLine1 [SAS::getCommandLine [pos::math $posBeg - 1] 0 1]
- set prevLine2 [SAS::getCommandLine [pos::math [lindex $prevLine1 0] - 1] 0 1]
- set lwhite [lindex $prevLine1 1]
- # If we have a previous line ...
- if {[pos::compare [lindex $prevLine1 0] != $posBeg]} {
- set pL1 [string trim [lindex $prevLine1 2]]
- # Indent if the last line did not terminate the command.
- if {![regexp {;([\t ]?)$} $pL1]} {
- incr lwhite $indent_amounts($continueIndent)
- }
- # Check to make sure that the previous command was not itself a
- # continuation of the line before it.
- if {[pos::compare [lindex $prevLine1 0] != [lindex $prevLine2 0]]} {
- set pL2 [string trim [lindex $prevLine2 2]]
- if {![regexp {;([\t ]?)$} $pL2]} {
- incr lwhite $indent_amounts(-$continueIndent)
- }
- }
- # Find out if there are any unbalanced {,},(,) in the last line.
- regsub -all {[^ \{\}\(\)\"\*\/\\]} $pL1 { } line
- # Remove all literals.
- regsub -all {\\\{|\\\}|\\\(|\\\)|\\\"|\\\*|\\\/} $line { } line
- regsub -all {\\} $line { } line
- # Remove everything surrounded by quotes.
- regsub -all {\"([^\"]+)\"} $line { } line
- regsub -all {\"} $line { } line
- # Remove everything surrounded by bracketed comments.
- regsub -all {/\*([^\*/]+)\*/} $line { } line
- # Now turn all braces into 2's and -2's
- regsub -all {\{|\(} $line { 2 } line
- regsub -all {\}|\)} $line { -2 } line
- # This list should now only contain 2's and -2's.
- foreach i $line {
- if {$i == "2" || $i == "-2"} {incr lwhite $indent_amounts($i)}
- }
- # Did the last line start with a lone \) or \} ? If so, we want to
- # keep the indent, and not make call it an unbalanced line.
- if {[regexp {^[\t ]*(\}|\))} $pL1]} {
- incr lwhite $indent_amounts(2)
- }
- }
- # If we have a current line ...
- if {[pos::compare [lindex $thisLine 0] == $posBeg]} {
- # Reduce the indent if the first non-whitespace character of this
- # line is ) or \}.
- set tL [lindex $thisLine 2]
- if {$next == "\}" || $next == ")" || [regexp {^[\t ]*(\}|\))} $tL]} {
- incr lwhite $indent_amounts(-2)
- }
- }
- # Now we return the level to the calling proc.
- return [expr {$lwhite > 0 ? $lwhite : 0}]
- }
-
- # ===========================================================================
- #
- # Get Command Line
- #
- # Find the next/prev command line relative to a given position, and return
- # the position in which it starts, its indentation, and the complete text
- # of the command line. If the search for the next/prev command fails,
- # return an indentation level of 0.
- #
-
- proc SAS::getCommandLine {pos {direction 1} {ignoreComments 1}} {
-
- if {$ignoreComments} {
- set pat {^[\t ]*[^\t\r\n\*/ ]}
- } else {
- set pat {^[\t ]*[^\t\r\n ]}
- }
- set posBeg [pos::math [lineStart $pos] - 1]
- if {[pos::compare $posBeg < [minPos]]} {
- set posBeg [minPos]
- }
- set lwhite 0
- if {![catch {search -f $direction -r 1 $pat $pos} match]} {
- set posBeg [lindex $match 0]
- set lwhite [posX [pos::math [lindex $match 1] - 1]]
- }
- set posEnd [pos::math [nextLineStart $posBeg] - 1]
- if {[pos::compare $posEnd > [maxPos]]} {
- set posEnd [maxPos]
- }
- return [list $posBeg $lwhite [getText $posBeg $posEnd]]
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Command Double Click ◊◊◊◊ #
- #
- # Checks to see if the highlighted word appears in any keyword list, and if
- # so, sends the selected word to the http://search.sas.com/ help site.
- #
- # (Default preference is not the most useful site, but the best I could find.)
- #
- # Control-Command double click will insert syntax information in status bar.
- # Shift-Command double click will insert commented syntax information in window.
- #
- # (The above is not yet implemented -- need to enter all of the syntax info.)
- #
-
- proc SAS::DblClick {from to shift option control} {
-
- global SASmodeVars SAScmds SASSyntaxMessage
-
- select $from $to
- set command [getSelect]
-
- if {[lsearch -exact $SAScmds $command] == -1} {
- message "\"$command\" is not defined as a SAS system keyword."
- return
- }
- # Defined as a keyword, determine if there's a syntax message.
- # Any modifiers pressed?
- if {$control} {
- # CONTROL -- Just put syntax message in status bar window
- if {[info exists SASSyntaxMessage($command)]} {
- message $SASSyntaxMessage($command)
- } else {
- message "Sorry, no syntax information available for $command"
- }
- } elseif {$shift} {
- # SHIFT --Just insert syntax message as commented text
- if {[info exists SASSyntaxMessage($command)]} {
- endOfLine
- insertText "\r"
- insertText "$SASSyntaxMessage($command)"
- comment::Line
- } else {
- message "Sorry, no syntax information available for $command"
- }
- } elseif {$option && !$SASmodeVars(localHelp)} {
- # Now we have four possibilities, based on "option" key and the
- # preference for "local Help Only". (Local Help Only actually
- # switches the "normal" behavior of options versus not.)
- #
- # OPTION, local help isn't checked -- Send command to local application
- SAS::localCommandHelp $command
- } elseif {$option && $SASmodeVars(localHelp)} {
- # OPTION, but local help is checked -- Send command for on-line help.
- SAS::wwwCommandHelp $command
- } elseif {$SASmodeVars(localHelp)} {
- # No modifiers, local help is checked -- Send command to local app.
- SAS::localCommandHelp $command
- } else {
- # No modifiers, no local help checked -- Send command for on-line
- # help. This is the "default" behavior.
- SAS::wwwCommandHelp $command
- }
- }
-
- # ===========================================================================
- #
- # WWW Command Help
- #
- # Send command to defined url, prompting for text if necessary.
- #
-
- proc SAS::wwwCommandHelp {{command ""}} {
-
- global SASmodeVars
-
- if {$command == ""} {
- set command [prompt "on-line SAS help for ... " [getSelect]]
- # set command [statusPrompt "on-line help for ... " ]
- }
- message "\"$command\" sent to $SASmodeVars(helpUrl)"
- icURL $SASmodeVars(helpUrl)$command
- }
-
- # ===========================================================================
- #
- # Local Command Help
- #
- # Send command to local application, prompting for text if necessary.
- #
-
- proc SAS::localCommandHelp {{command ""} {app "SAS"}} {
-
- SAS::betaMessage
-
- global SASmodeVars tcl_platform
-
- if {$command == ""} {
- set command [prompt "local $app application help for ... " [getSelect]]
- # set command [statusPrompt "local $app application help for ..." ]
- }
- set pf $tcl_platform(platform)
-
- # We have three possible options here, based on platform.
-
- if {$pf == "macintosh"} {
- # Make sure that the Macintosh application for the signature exists.
- if {[catch {[nameFromAppl [SAS::sig]]}]} {
- SAS::selectApplication $app
- }
- } elseif {$pf == "windows" || $pf == "unix"} {
- # Make sure that the Windows application for the signature exists.
- # We assume that this will work for unix, too.
- if {![file exists [S::sig]]} {
- SAS::selectApplication $app
- }
- }
- # Now we actually do something ...
- }
-
-
- # ===========================================================================
- #
- # ◊◊◊◊ Mark File and Parse Functions ◊◊◊◊ #
- #
-
- # ===========================================================================
- #
- # SAS Mark File
- #
- # This will return the first 35 characters from the first non-commented
- # word that appears in column 0. All other output files (those not
- # recognized) will take into account the additional left margin elements
- # added by SAS.
- #
-
- proc SAS::MarkFile {{type ""}} {
-
- removeAllMarks
-
- message "Marking File …"
-
- set pos [minPos]
- set count 0
- # Figure out what type of file this is -- source, or output.
- # The variable "type" refers to a call from the SAS menu.
- # Otherwise we try to figure out the type based on the file's suffix.
- if {$type == ""} {
- if {[win::CurrentTail] == "* SAS Mode Example *"} {
- # Special case for Mode Examples, but only if called from
- # Marks menu. (Called from SAS menu, "type" will over-ride.
- set type ".sas"
- } else {
- set type [file extension [win::CurrentTail]]
- }
- }
- # Now set the mark regexp.
- if {$type == ".sas" } {
- # Source file.
- set markExpr {^(\*\*\*[ ]|\*\*\*\*[ ])?[a-zA-Z0-9]}
- } else {
- # None of the above, so assume that it's output
- set markExpr {^([0-9]+(( )|( )))+(\*\*\*[ ]|\*\*\*\*[ ])?[a-zA-Z0-9]}
- }
- # Mark the file
- while {![catch {search -s -f 1 -r 1 -m 0 -i 1 $markExpr $pos} match]} {
- incr count
- set posBeg [lindex $match 0]
- set posEnd [nextLineStart $posBeg]
- if {[pos::compare $posEnd > [maxPos]]} {set posEnd [maxPos]}
- set line [string trimright [getText $posBeg $posEnd]]
- # Get rid of the leading "[0-9] " for output files
- regsub {^[0-9]*[0-9]*[0-9]*[0-9]} $line {} line
- # Get rid of braces.
- regsub -all {\{|\[} $line {(} line
- regsub -all {\}|\]} $line {)} line
- set line [string trimleft $line " "]
- set line " $line"
- if {[regsub { \*\*\*\* } $line {* } line]} {
- incr count -1
- } elseif {[regsub { \*\*\* } $line {• } line]} {
- incr count -1
- }
- if {[string length $line] > 35} {
- set line "[string range $line 0 35] ..."
- } else {
- # Get rid of trailing semi-colons.
- set line [string trimright $line ";" ]
- }
- # If the mark starts with "run", ignore it.
- if {![regexp {^ (run|RUN)} $line]} {
- setNamedMark $line $posBeg $posBeg $posBeg
- }
- set pos $posEnd
- }
- message "This file contains $count commands."
- }
-
- # ===========================================================================
- #
- # SAS Parse Functions
- #
- # This will return only the SAS command names.
- #
-
- proc SAS::parseFuncs {} {
-
- global sortFuncsMenu
-
- set pos [minPos]
- set m {}
- while {[set match [search -s -f 1 -r 1 -i 0 -n {^(\w+)} $pos]] != ""} {
- if {[regexp -- {^(\w+)} [eval getText $match] "" word]} {
- lappend m [list $word [lindex $match 0]]
- }
- set pos [lindex $match 1]
- }
- if {$sortFuncsMenu} {
- regsub -all "\[\{\}\]" [lsort -ignore $m] "" m
- } else {
- regsub -all "\[\{\}\]" $m "" m
- }
- return $m
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ -------------------- ◊◊◊◊ #
- #
- # ◊◊◊◊ SAS Menu ◊◊◊◊ #
- #
- # based upon the Stata menu, contributed by
- # L. Phillip Schumm <pschumm@uchicago.edu>
- #
-
- # Tell Alpha what procedures to use to build all menus, submenus.
-
- menu::buildProc sasMenu SAS::buildMenu
- menu::buildProc sasHelp SAS::buildHelpMenu
- menu::buildProc sasKeywords SAS::buildKeywordsMenu
- menu::buildProc markSasFileAs… SAS::buildMarkMenu
-
- # First build the main SAS menu.
-
- proc SAS::buildMenu {} {
-
- global sasMenu
-
- set menuList [list \
- "sasHomePage" \
- "/S<U<OswitchToSas" \
- [list Menu -n sasHelp -M SAS {}] \
- "(-" \
- [list Menu -n sasKeywords -M SAS {}] \
- [list Menu -n markSasFileAs… -M SAS {}] \
- "(-" \
- "/P<U<OprocessFile" \
- "/P<U<O<BprocessSelection" \
- "(-" \
- "/I<U<OinsertPath" \
- "(-" \
- "/N<U<BnextCommand" \
- "/P<U<BprevCommand" \
- "/S<U<BselectCommand" \
- "/I<B<OreformatCommand" \
- ]
- set submenus [list markSasFileAs… sasHelp sasKeywords]
- return [list build $menuList SAS::menuProc $submenus $sasMenu]
- }
-
- # Then build the "SAS Help" submenu.
-
- proc SAS::buildHelpMenu {} {
-
- global SASmodeVars SASPrefsInMenu alpha::platform
-
- # Determine which key should be used for "Help", with F8 as option.
-
- if {!$SASmodeVars(noHelpKey)} {
- set key "/t"
- } else {
- set key "/l"
- }
-
- # Reverse the local, www key bindings depending on the value of the
- # 'Local Help" variable.
-
- if {!$SASmodeVars(localHelp)} {
- set menuList [list \
- "${key}<OwwwCommandHelp…" \
- "${key}<IlocalCommandHelp…" \
- ]
- } else {
- set menuList [list \
- "${key}<OlocalCommandHelp…" \
- "${key}<IwwwCommandHelp…" \
- ]
- }
- lappend menuList "(-"
- if {${alpha::platform} == "alpha"} {
- set prefix "!√"
- } else {
- set prefix "!•"
- }
- foreach pref $SASPrefsInMenu {
- if {$SASmodeVars($pref)} {
- lappend menuList "${prefix}$pref"
- } else {
- lappend menuList "$pref"
- }
- }
- lappend menuList "(-"
- lappend menuList "checkKeywords"
- lappend menuList "addNewCommands"
- lappend menuList "addNewArguments"
- lappend menuList "setSasApplication"
- lappend menuList "(-"
- lappend menuList "${key}<BsasModeHelp"
-
- return [list build $menuList SAS::helpProc {}]
- }
-
- # Then build the "SAS Mode Keywords" submenu.
-
- proc SAS::buildKeywordsMenu {} {
-
- set menuList [list \
- "listKeywords" \
- "checkKeywords" \
- "addNewCommands" \
- "addNewArguments" \
- ]
- return [list build $menuList SAS::keywordsProc {}]
- }
-
- # Then build the "Mark SAS File As" submenu.
-
- proc SAS::buildMarkMenu {} {
-
- global SASmodeVars alpha::platform
-
- set menuList [list \
- "source" \
- "output" \
- "(-" \
- ]
- if {${alpha::platform} == "alpha"} {
- set prefix "!√"
- } else {
- set prefix "!•"
- }
- if {$SASmodeVars(autoMark)} {
- lappend menuList "${prefix}autoMark"
- } else {
- lappend menuList "autoMark"
- }
- return [list build $menuList SAS::markFileProc {}]
- }
-
- proc SAS::rebuildMenu {{menuName "sasMenu"} {pref ""}} {
- menu::buildSome $menuName
- }
-
- # Dim some menu items when there are no open windows.
- set menuItems {
- processFile processSelection markSasFileAs
- insertPath
- nextCommand prevCommand selectCommand
- }
- foreach i $menuItems {
- hook::register requireOpenWindowsHook [list sasMenu $i] 1
- }
- unset i menuItems
-
- # Now we actually build the SAS menu.
-
- menu::buildSome sasMenu
-
-
- # ===========================================================================
- #
- # ◊◊◊◊ SAS menu support ◊◊◊◊ #
- #
-
- # This is the procedure called for all main menu items.
-
- proc SAS::menuProc {menu item} {
- SAS::$item
- }
-
- # Give a beta message for untested features / menu items.
-
- proc SAS::betaMessage {{kill 1}} {
-
- beep ; message "Sorry, this feature has not been fully implemented."
- if {$kill} {return -code return}
- }
-
- # ===========================================================================
- #
- # Open the SAS home page.
- #
-
- proc SAS::sasHomePage {} {
-
- global SASmodeVars
-
- url::execute $SASmodeVars(sasHomePage)
- }
-
- # ===========================================================================
- #
- # Switch to SAS application
- #
-
- proc SAS::switchToSas {} {app::launchFore [SAS::sig]}
-
- # ===========================================================================
- #
- # Return the SAS signature.
- #
-
- proc SAS::sig {{app "SAS"}} {
-
- global SASmodeVars
-
- set lowApp [string tolower $app]
- set capApp [string toupper $app]
- if {$SASmodeVars(${lowApp}Sig) == ""} {
- alertnote "Looking for the $capApp application ..."
- SAS::setApplication $lowApp
- }
- return $SASmodeVars(${lowApp}Sig)
- }
-
- # ===========================================================================
- #
- # Set Application
- #
- # Prompt the user to locate the local SAS application.
- #
-
- proc SAS::setApplication {{app "SAS"}} {
-
- global mode SASmodeVars
-
- set lowApp [string tolower $app]
- set capApp [string toupper $app]
-
- set newSig ""
- set newSig [dialog::askFindApp $capApp $SASmodeVars(${lowApp}Sig)]
-
- if {$newSig != ""} {
- set SASmodeVars(${lowApp}Sig) "$newSig"
- set oldMode $mode
- set mode "SAS"
- synchroniseModeVar "${lowApp}Sig" $SASmodeVars(${lowApp}Sig)
- set mode $oldMode
- message "The $capApp signature has been changed to \"$newSig\"."
- } else {
- message "Cancelled."
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Help ◊◊◊◊ #
- #
-
- proc SAS::helpProc {menu item} {
-
- global SASmodeVars SASPrefsInMenu
-
- if {$item == "wwwCommandHelp"} {
- SAS::wwwCommandHelp
- } elseif {$item == "localCommandHelp"} {
- SAS::localCommandHelp
- } elseif {[lsearch -exact $SASPrefsInMenu $item] != -1} {
- SAS::flagFlip $item
- SAS::rebuildMenu sasHelp
- } elseif {$item == "setSasApplication"} {
- SAS::selectApplication "SAS"
- } elseif {$item == "sasModeHelp"} {
- package::helpFile "SAS"
- } else {
- SAS::$item
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Keywords ◊◊◊◊ #
- #
-
- proc SAS::keywordsProc {menuName item} {
-
- global SASlowerCaseCmds
-
- if {$item == "listKeywords"} {
- set keywords [listpick -l -p "Current SAS mode keywords…" $SASlowerCaseCmds]
- foreach keyword $keywords {
- SAS::checkKeywords $keyword
- }
- } elseif {$item == "addNewCommands" || $item == "addNewArguments"} {
- set item [string trimleft $item "addNew"]
- if {$item == "Commands" && [llength [winNames]] && [askyesno \
- "Would you like to add all of the \"extra\" commands from this window\
- to the \"Add Commands\" preference?"] == "yes"} {
- SAS::addWindowCommands
- } else {
- SAS::addKeywords $item
- }
- } else {
- SAS::$item
- }
- }
-
- # ===========================================================================
- #
- # SAS::addWindowCommands
- #
- # Add all of the "extra" commands which appear in entries in this window.
- #
-
- proc SAS::addWindowCommands {} {
-
- global mode SAScmds SASmodeVars
-
- if {![llength [winNames]]} {
- message "Cancelled -- no current window!"
- return
- }
-
- message "Scanning [win::CurrentTail] for all commands…"
-
- set pos [minPos]
- set pat {^([a-zA-Z0-9]+[a-zA-Z0-9])+[\t ]}
- while {![catch {search -f 1 -r 1 $pat $pos} match]} {
- set pos [nextLineStart [lindex $match 1]]
- set commandLine [getText [lindex $match 0] [lindex $match 1]]
- regexp $pat $commandLine match aCommand
- set aCommand [string tolower $aCommand]
- if {![lcontains SAScmds $aCommand]} {
- append SASmodeVars(addCommands) " $aCommand"
- }
- }
- set SASmodeVars(addCommands) [lsort [lunique $SASmodeVars(addCommands)]]
- set oldMode $mode
- set mode "SAS"
- synchroniseModeVar addCommands $SASmodeVars(addCommands)
- set mode $oldMode
- if {[llength $SASmodeVars(addCommands)]} {
- SAS::colorizeSAS
- listpick -p "The \"Add Commands\" preference includes:" \
- $SASmodeVars(addCommands)
- message "Use the \"Mode Prefs --> Preferences\" menu item to edit keyword lists."
- } else {
- message "No \"extra\" commands from this window were found."
- }
- }
-
- proc SAS::addKeywords {{category} {keywords ""}} {
-
- global mode SASmodeVars
-
- if {$keywords == ""} {
- set keywords [prompt "Enter new SAS $category:" ""]
- }
-
- # The list of keywords should all be lower case.
- set keywords [string tolower $keywords]
- # Check to see if the keyword is already defined.
- foreach keyword $keywords {
- set checkStatus [Lisp::checkKeywords $keyword 1 0]
- if {$checkStatus != "0"} {
- alertnote "Sorry, \"$keyword\" is already defined\
- in the $checkStatus list."
- message "Cancelled."
- return -code return
- }
- }
- # Keywords are all new, so add them to the appropriate mode preference.
- append SASmodeVars(add$category) " $keywords"
- set SASmodeVars(add$category) [lsort $SASmodeVars(add$category)]
- set oldMode $mode
- set mode "SAS"
- synchroniseModeVar add$category $SASmodeVars(add$category)
- set mode $oldMode
- SAS::colorizeSAS
- message "\"$keywords\" added to $category preference."
- }
-
- proc SAS::checkKeywords {{newKeywordList ""} {quietly 0} {noPrefs 0}} {
-
- global SASmodeVars
-
- global SASCommands SASUserCommands SASSubprocs
- global SASArguments SASUserArguments SASOptions SASParameters
-
- set type 0
- if {$newKeywordList == ""} {
- set quietly 0
- set newKeywordList [prompt "Enter SAS mode keywords to be checked:" ""]
- }
- # Check to see if the new keyword(s) is already defined.
- foreach newKeyword $newKeywordList {
- if {[lsearch -exact $SASCommands $newKeyword] != "-1"} {
- set type SASCommands
- } elseif {[lsearch -exact $SASUserCommands $newKeyword] != "-1"} {
- set type SASUserCommands
- } elseif {[lsearch -exact $SASSubprocs $newKeyword] != "-1"} {
- set type SASSubprocs
- } elseif {[lsearch -exact $SASArguments $newKeyword] != "-1"} {
- set type SASArguments
- } elseif {[lsearch -exact $SASUserArguments $newKeyword] != "-1"} {
- set type SASUserArguments
- } elseif {[lsearch -exact $SASOptions $newKeyword] != "-1"} {
- set type SASOptions
- } elseif {[lsearch -exact $SASParameters $newKeyword] != "-1"} {
- set type SASParameters
- } elseif {!$noPrefs && \
- [lsearch -exact $SASmodeVars(addCommands) $newKeyword] != "-1"} {
- set type SASmodeVars(addCommands)
- } elseif {!$noPrefs && \
- [lsearch -exact $SASmodeVars(addArguments) $newKeyword] != "-1"} {
- set type SASmodeVars(addArguments)
- }
- if {$quietly} {
- # When this is called from other code, it should only contain
- # one keyword to be checked, and we'll return it's type.
- return "$type"
- } elseif {!$quietly && $type == 0} {
- alertnote "\"$newKeyword\" is not currently defined\
- as a SAS mode keyword"
- } elseif {$type != 0} {
- # This will work for any other value for "quietly", such as "2"
- alertnote "\"$newKeyword\" is currently defined as a keyword\
- in the \"$type\" list."
- }
- set type 0
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Marks ◊◊◊◊ #
- #
-
- proc SAS::markFileProc {menu item} {
-
- if {$item == "source"} {
- SAS::MarkFile {.sas}
- } elseif {$item == "output"} {
- # doesn't really matter what we put for the mark file "type" here,
- # since output is the default if other "if ..." cases aren't met.
- SAS::MarkFile {.out}
- } elseif {$item == "autoMark"} {
- SAS::flagFlip autoMark
- SAS::rebuildMenu markSasFileAs…
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Processing ◊◊◊◊ #
- #
-
- # ===========================================================================
- #
- # Process File
- #
-
- # Send entire file to SAS for processing, adding carriage return at end
- # of file if necessary.
- #
- # Optional "f" argument allows this to be called by other code, or to be
- # sent via a Tcl shell window.
- #
-
- proc SAS::processFile {{f ""} {app "SAS"}} {
-
- if {$f != ""} {file::openAny $f}
- set f [win::Current]
-
- set dirtyWindow [winDirty]
- set dontSave 0
- if {$dirtyWindow && [askyesno \
- "Do you want to save the file before sending it to SAS?"] == "yes"} {
- save
- } else {
- set dontSave 1
- }
- if {!$dontSave && [lookAt [pos::math [maxPos] - 1]] != "\r"} {
- set pos [getPos]
- goto [maxPos]
- insertText "\r"
- goto $pos
- alertnote "Carriage return added to end of file."
- save
- }
-
- app::launchBack '[SAS::sig]'
- sendOpenEvent noReply '[SAS::sig]' $f
- switchTo '[SAS::sig]'
- }
-
- # ===========================================================================
- #
- # Process Selection
- #
- # Procedure to implement transfer of selected lines to SAS for processing.
- #
-
- proc SAS::processSelection {{selection ""} {app "SAS"}} {
-
- global PREFS
-
- if {$selection == ""} {
- if {![isSelection]} {
- message "No selection -- cancelled."
- return
- } else {
- set selection [getSelect]
- }
- }
- file::ensureDirExists [file join $PREFS SAS-tmp]
- set newFile [file join $PREFS SAS-tmp temp-SAS.do]
- file::writeAll $newFile $selection 1
-
- app::launchBack '[SAS::sig]'
- sendOpenEvent noReply '[SAS::sig]' $newFile
- switchTo '[SAS::sig]'
- }
-
- proc SAS::quitHook {} {temp::cleanup SAS-tmp}
-
- # ===========================================================================
- #
- # ◊◊◊◊ Insertions ◊◊◊◊ #
- #
-
- proc SAS::insertPath {} {
-
- global file::separator
-
- set path ""
- set t ""
- append t "\"${file::separator}"
- set path [getfile "Choose path of target file:"]
- if {$path != ""} {
- append t $path
- append t "\""
- insertText $t
- }
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ Navigation ◊◊◊◊ #
- #
-
- # Next/Prev command can simply return the position of the next command
- # (quietly == 1), move the cursor to the next command (placing the cursor
- # at the top of the window if toTop == 1), extend the current selection to
- # the end of the this command, or (if the current command is already
- # highlighted in its entirety) extend the current selection to the end of
- # the next command.
- #
-
- proc SAS::nextCommand {{quietly 0} {toTop 0}} {
-
- if {[pos::compare [selEnd] == [maxPos]]} {
- set pos [maxPos]
- } else {
- set pos [pos::math [selEnd] + 1]
- }
- set pat {^[^\r\n\t \*/]}
-
- if {![catch {search -f 1 -r 1 $pat $pos} match]} {
- set pos [lineStart [lindex $match 1]]
- } else {
- set pos [maxPos]
- }
- if {$quietly} {
- return $pos
- } elseif {[isSelection]} {
- set limit1 [lindex [SAS::getCommand [selEnd]] 1]
- set limit2 [lindex [SAS::getCommand $pos ] 1]
- if {$limit2 == "-1"} {set limit2 [maxPos]}
- if {$limit1 == "-1"} {set limit1 $limit2}
- if {[pos::compare [selEnd] < $limit1]} {
- select [getPos] $limit1
- } else {
- select [getPos] $limit2
- }
- } elseif {$pos == [maxPos]} {
- message "No further commands in the file."
- return
- } else {
- goto $pos
- message [getText $pos [nextLineStart $pos]]
- }
- if {$toTop} {insertToTop}
- }
-
- proc SAS::prevCommand {{quietly 0} {toTop 0}} {
-
- if {[pos::compare [getPos] == [minPos]]} {
- set pos [minPos]
- } else {
- set pos [pos::math [getPos] - 1]
- }
- set pat {^[^\r\n\t \*/]}
-
- if {![catch {search -f 0 -r 1 $pat $pos} match]} {
- set pos [lineStart [lindex $match 1]]
- } else {
- set pos [minPos]
- }
- if {$quietly} {
- return $pos
- } elseif {[isSelection]} {
- # Going backwards is actually easier with selections.
- select $pos [selEnd]
- } elseif {$pos == [minPos]} {
- message "No further commands in the file."
- return
- } else {
- goto $pos
- message [getText $pos [nextLineStart $pos]]
- }
- if {$toTop} {insertToTop}
- return $pos
- }
-
- proc SAS::searchFunc {direction} {
-
- if {$direction} {
- SAS::nextCommand
- } else {
- SAS::prevCommand
- }
- }
-
- proc SAS::selectCommand {} {
-
- set pos [getPos]
- set limits [SAS::getCommand $pos]
- set posBeg [lindex $limits 0]
- set posEnd [lindex $limits 1]
-
- if {$posBeg != "-1" && $posEnd != "-1" && \
- [pos::compare $pos >= $posBeg] && [pos::compare $pos <= $posEnd]} {
- select $posBeg $posEnd
- } else {
- message "The cursor is not within a command."
- error "The cursor is not within a command."
- }
- }
-
- proc SAS::copyCommand {{quietly 0}} {
-
- set pos [getPos]
- if {[set posBeg [lindex [SAS::getCommand $pos] 0]] != "-1"} {
- goto $posBeg
- forwardWord
- set posEnd [getPos]
- if {!$quietly} {
- select $posBeg $posEnd
- copy
- message "\"[getText $posBeg $posEnd]\" copied to clipboard."
- }
- goto $pos
- return [getText $posBeg $posEnd]
- } elseif {!$quietly} {
- message "The cursor is not within a command."
- }
- return ""
- }
-
- proc SAS::reformatCommand {} {
-
- if {![isSelection]} {SAS::selectCommand}
- message "Reformatting …"
- ::indentRegion
- goto [pos::math [getPos] -1]
- goto [SAS::nextCommand 1]
- message "Reformatted."
- }
-
- proc SAS::getCommand {pos} {
-
- set pos1 [pos::math [nextLineStart $pos] - 1]
- set pat {^[^\r\n\t \}\)]}
- set posBeg "-1"
- set posEnd "-1"
- if {![catch {search -f 0 -r 1 $pat $pos1} match]} {
- set posBeg [lindex $match 0]
- set pos2 [nextLineStart $posBeg]
- if {![catch {search -f 1 -r 1 $pat $pos2} match]} {
- set posEnd [lindex $match 0]
- } else {
- set posEnd [maxPos]
- }
- # Now back up to remove empty or commented lines.
- set posEndPrev [pos::math $posEnd - 1]
- set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
- while {[regexp {^[\t ]*$} $prevLine]} {
- set posEnd [lineStart $posEndPrev]
- set posEndPrev [pos::math $posEnd - 1]
- set prevLine [getText [lineStart $posEndPrev] $posEndPrev]
- }
- }
- return [list $posBeg $posEnd]
- }
-
- # ===========================================================================
- #
- # ◊◊◊◊ --------------------- ◊◊◊◊ #
- #
- # ◊◊◊◊ version history ◊◊◊◊ #
- #
- # modified by vers# reason
- # -------- --- ------ -----------
- # 01/28/20 cbu 1.0.1 First created sas mode, based upon other modes found
- # in Alpha's distribution. Commands are based on
- # version 2.0.1 of SAS.
- # 03/02/20 cbu 1.0.2 Minor modifications to comment handling.
- # 03/20/00 cbu 1.0.3 Minor update of keywords dictionaries.
- # Renamed mode SAS, from sas
- # 04/01/00 cbu 1.0.4 Fixed a little bug with "comment box".
- # Added new preferences to allow the user to enter
- # additional commands and options.
- # Reduced the number of different user-specified colors.
- # Added "Update Colors" proc to avoid need for a restart
- # 04/08/00 cbu 1.0.5 Unset obsolete preferences from earlier versions.
- # Modified "Electric Semi" added "Continue Comment" and
- # "Electric Return Over-ride".
- # Renamed "Update Colors" to "Update Preferences".
- # 04/16/00 cbu 1.1 Renamed to sasMode.tcl
- # Added "Mark File" and "Parse Functions" procs.
- # 06/22/00 cbu 1.2 "Mark File" now recognizes headings as well as commands.
- # "Mark File" recognizes source or output files.
- # Completions, Completions Tutorial added.
- # "Reload Completions", referenced by "Update Preferences".
- # Better support for user defined keywords.
- # Removed "Continue Comment", now global in Alpha 7.4.
- # Added command double-click for on-line help.
- # <shift, control>-<command> double-click syntax info.
- # (Foundations, at least. Ongoing project.)
- # 06/22/00 cbu 1.2.1 "Mark File"ignores "run" commands.
- # Minor keywords update.
- # Beta-version of a SAS menu, based on the Stata menu.
- # Added "sasSig" preference to allow user to find
- # local application if necessary.
- # Added SAS::sig which returns SAS signature.
- # 08/28/00 cbu 1.2.2 Added some of the flag preferences to "SAS Help" menu.
- # Added "flagFlip" to update preference bullets in menu.
- # Added a "noHelpKey" preference, which switches the
- # "help" key binding to F8.
- # Added "Add New Commands / Arguments" to "SAS Help" menu.
- # Added "Set SAS Application to "SAS Help" menu.
- # 11/05/00 cbu 1.3 Added "next/prevCommand", "selectCommand", and
- # "copyCommand" procs to menu.
- # Added "SAS::indentLine".
- # Added "SAS::reformatCommand" to menu.
- # "SAS::reloadCompletions" is now obsolete.
- # "SAS::updatePreferences" is now obsolete.
- # "SAS::colorizeSAS" now takes care of setting all
- # keyword lists, including SAScmds.
- # Cleaned up completion procs. This file never has to be
- # reloaded. (Similar cleaning up for "SAS::DblClick").
- # 11/16/00 cbu 2.0 New url prefs handling requires 7.4b21
- # Added "Home Page" pref, menu item.
- # Removed hook::register requireOpenWindowsHook from
- # mode declaration, put it after menu build.
- # 12/19/00 cbu 2.1 The menu proc "Add Commands" now includes an option
- # to grab all of the "extra" command from the current
- # window, using SAS::addWindowCommands.
- # Added "Keywords" submenu, "List Keywords" menu item.
- # Big cleanup of ::sig, ::setApplication, processing ...
- # 01/25/01 cbu 2.1.1 Bug fix for SAS::processSelection/File.
- # Bug fix for comment characters.
- #
-
- # ===========================================================================
- #
- # .
-